/*
Copyright 2008, 2009, 2010 Brightworks, Inc.

This file is part of Language Mentor.

Language Mentor is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Language Mentor is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Language Mentor.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.langcollab.languagementor.controller.audio
{
    import com.brightworks.util.Debug;

    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.SampleDataEvent;
    import flash.media.Microphone;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.utils.ByteArray;

    [Event(name="soundComplete", type="flash.events.Event")]

    public class AudioRecorder extends EventDispatcher
    {
        private static var _bHasRecordedContent:Boolean = false;

        private static var _instance:com.langcollab.languagementor.controller.audio.AudioRecorder;
        private var _microphone:Microphone;
        private var _playbackChannel:SoundChannel;
        private var _playbackSound:Sound;
        private var _recordedAudio:ByteArray;

        public static function getInstance():com.langcollab.languagementor.controller.audio.AudioRecorder
        {
            if ( _instance == null )
            {
                _instance = new com.langcollab.languagementor.controller.audio.AudioRecorder();
            }
            return _instance;
        }

        public function AudioRecorder()
        {
            if (_instance)
            {
                Debug.error_Fatal("Don't instantiate AudioRecorder with new() - use getInstance()");
            }
        }

        // ****************************************************
        //
        //          Public Methods
        //
        // ****************************************************

        public function clear():void
        {
            if (_microphone)
                _microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, onNewRecordingSampleData);
            if (_playbackSound)
                _playbackSound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onGetPlaybackSampleData);
            if (_playbackChannel)
                _playbackChannel.removeEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
            _bHasRecordedContent = false;
            _microphone = null;
            _playbackSound = null;
            _playbackChannel = null;
            _recordedAudio = null;
        }

        public function isMicrophoneAvailable():Boolean
        {
            return (Microphone.getMicrophone()) ? true : false;
        }

        public function startPlayback():void
        {
            _recordedAudio.position = 0;
            _playbackSound = new Sound();
            _playbackSound.addEventListener(SampleDataEvent.SAMPLE_DATA, onGetPlaybackSampleData);
            _playbackChannel = _playbackSound.play();
            _playbackChannel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
        }

        public function startRecording():void
        {
            _microphone = Microphone.getMicrophone();
            _microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, onNewRecordingSampleData);
            _microphone.rate = 44;
            _microphone.gain = 40;  // TODO - make this adjustable, or adjust it dynamically?
            _microphone.setSilenceLevel(0, 2000);
            _bHasRecordedContent = true;
            _recordedAudio = new ByteArray();
        }

        public function stopPlayback():void
        {
            clear();
        }

        public function stopRecording():void
        {
            _microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, onNewRecordingSampleData);
        }

        // ****************************************************
        //
        //          Public Methods
        //
        // ****************************************************

        private function onPlaybackComplete(event:Event):void
        {
            clear();
            dispatchEvent(new Event(Event.SOUND_COMPLETE));
        }

        private function onGetPlaybackSampleData(event:SampleDataEvent):void
        {
            if (_recordedAudio.bytesAvailable <= 0)
                return;
            for (var i:int = 0; i < 8192; i++)
            {
                var sample:Number = 0;
                if (_recordedAudio.bytesAvailable > 0)
                {
                    sample = _recordedAudio.readFloat();
                }
                event.data.writeFloat(sample); 
                event.data.writeFloat(sample);  
            }
        }

        private function onNewRecordingSampleData(event:SampleDataEvent):void
        {
            if (_recordedAudio)
            {
                _recordedAudio.writeBytes(event.data);
            }
        }
    }
}

